/**
* \file DGVImage.cpp
*
* \brief This file defines the class for displaying images using only Qt.
* \author Shekhar S. Chandra, 2008
*
* This file is part of DGV Library.
*
* DGV is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* DGV is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with DGV.  If not, see <http://www.gnu.org/licenses/>.
*/
#include "DGVImage.h"

DGVImage::DGVImage(QWidget *parent) : QLabel(parent)
{
    loadComplete = false;

    createActions();
    createConnections();
}

DGVImage::DGVImage(Array<imageType,2> &data, QWidget *parent) : QLabel(parent)
{
    loadComplete = false;

    createActions();
    createConnections();

    setPixmap(data);
}

DGVImage::~DGVImage()
{

}

void DGVImage::setName(QString filename)
{
    name = filename;
    setWindowTitle(strippedNamePrefix());
}

bool DGVImage::openImage(QString filename)
{
    if(!filename.isEmpty())
    {
        QPixmap pix;
        name = filename;

        ///Set the image into the viewer
        pix.load(name);
        DGVImage::setPixmap(pix);
        QLabel::setWindowTitle(strippedName());
        QLabel::update();

        return true;
    }
    else
        return false;
}

void DGVImage::linkResult(DGVImage *result)
{
    resultImage = result;
}

void DGVImage::setPixmap(const QPixmap &pix)
{
    QImage image;

    image = pix.toImage();
    Blitz.QImageToArray(&image,imageData);
    cerr << "Warning: Data Overwriten in Memory!" << endl;

    refreshImage();
}

void DGVImage::setPixmap(const Array<imageType,2> &bins)
{
    QImage *image;
    QPixmap pix;

    imageData.resize(bins.rows(),bins.cols());
    imageData = bins;

    image = Blitz.arrayToQImage(bins);

    pix = pix.fromImage(*image);
    cerr << "Warning: Data Overwriten!" << endl;

    QLabel::setPixmap(pix); ///call the original setPixmap member (of base class).
    QLabel::adjustSize();
    QLabel::setScaledContents(true);
    QLabel::update();
    loadComplete = true;
}

void DGVImage::setInterpolation(bool interpolation)
{
    if(interpolation)
        cerr << "Turning Interpolation/Anti-Aliasing ON" << endl;
    else
        cerr << "Turning Interpolation/Anti-Aliasing OFF" << endl;
    //QLabel::paintEngine()->painter()->setRenderHint(QPainter::Antialiasing, interpolation);
    QLabel::update();
}

QString DGVImage::strippedName()
{
    return QFileInfo(name).fileName();
}

QString DGVImage::strippedNamePrefix()
{
    return "Image: " + QFileInfo(name).fileName();
}

//Slots
void DGVImage::table()
{
    dataTable = new DGVTable(this);
    QString tmp;

    dataTable->setData(imageData);

    connectTable(dataTable);

    emit tableAvailable(dataTable);
}

void DGVImage::updateData(int row, int col)
{
    imageData(row,col) = dataTable->item(row,col)->text().toDouble();
}

void DGVImage::refreshImage()
{
    setPixmap(imageData);
    QLabel::adjustSize();
    QLabel::setScaledContents(true);
    QLabel::update();
    loadComplete = true;
}

void DGVImage::normGreyscale()
{
    QImage image(imageData.cols(),imageData.rows(),QImage::Format_Indexed8);
    QPixmap pix;
    imageType tmp = 0, max = 0, min = 0;

    if(loadComplete)
    {
        image = pixmap()->toImage();

        ///Find Max
        if(imageData.cols() > 0 && imageData.rows() > 0)
            min = max = qGray(image.pixel(0,0));

        for(int j = 0; j < imageData.rows(); j ++)
            for(int k = 0; k < imageData.cols(); k ++)
            {
                if(max < qGray(image.pixel(k,j)))
                    max = qGray(image.pixel(k,j));
                if(min > qGray(image.pixel(k,j)))
                    min = qGray(image.pixel(k,j));
            }
        qDebug() << "\nNorm - Max Pixel: " << max << ", Min Pixel: " << min;
        max -= min;

        ///Set colour table
        image.setNumColors(256);
        for(int j = 0; j < 256; j ++)
            image.setColor(j,qRgb(j, j, j));

        ///Scaling is required
        for(int j = 0; j < imageData.rows(); j ++)
            for(int k = 0; k < imageData.cols(); k ++)
            {
                tmp = static_cast<imageType>( (qGray(image.pixel(k,j))-min)/static_cast<double>(max)*255.0 );
                //cerr << " tmp: " << tmp << ", " << qGray(image.pixel(k,j));
                image.setPixel(k,j,qRgb(static_cast<int>(tmp),static_cast<int>(tmp),static_cast<int>(tmp)));
            }

        pix = pix.fromImage(image);

        QLabel::setPixmap(pix); ///call the original setPixmap member (of base class).
        QLabel::adjustSize();
        QLabel::setScaledContents(true);
        QLabel::update();
    }
}

void DGVImage::save()
{
    QFileDialog *fileSaver = new QFileDialog(this);
    QString filename = fileSaver->getSaveFileName(this,
                           "Select File Name to Save",
                           ".",
                           "Images (*.png *.ppm *.jpeg *.jpg *.bmp)");

    if (!filename.isEmpty())
        pixmap()->save(filename);
}

void DGVImage::createActions()
{
    normGreyAct = new QAction(tr("&Normalise Greyscale"), this);
    normGreyAct->setShortcut(tr("Ctrl+n"));
    interpolateAct = new QAction(tr("&Interpolation"), this);
    interpolateAct->setCheckable(true);
    interpolateAct->setChecked(true);
    interpolateAct->setShortcut(tr("Ctrl+i"));
}

void DGVImage::createConnections()
{
    ///When triggered, create embed dialog and let Main Window know
    connect(normGreyAct, SIGNAL(triggered()), this, SLOT(normGreyscale()));
    connect(interpolateAct, SIGNAL(triggered(bool)), this, SLOT(setInterpolation(bool)));
}

void DGVImage::connectTable(DGVTable *child)
{
    QObject::connect(child,SIGNAL(cellChanged(int,int)), this, SLOT(updateData(int,int)));
}

void DGVImage::contextMenuEvent(QContextMenuEvent *event)
{
    QMenu menu(this);

    ///Image Operations Menu
    imageMenu = menu.addMenu("Image");
    imageMenu->addAction(normGreyAct);
    imageMenu->addAction(interpolateAct);
    ///Setup Data action
    tableAct = menu.addAction(tr("&Data"));
    tableAct->setShortcut(tr("Ctrl+d"));
    connect(tableAct, SIGNAL(triggered()), this, SLOT(table()));
    menu.addSeparator();
    ///Setup Refresh action
    refreshAct = menu.addAction(tr("&Refresh"));
    refreshAct->setShortcut(tr("Ctrl+r"));
    connect(refreshAct, SIGNAL(triggered()), this, SLOT(refreshImage()));
    ///Setup Save action
    saveAct = menu.addAction(tr("&Save"));
    saveAct->setShortcut(tr("Ctrl+S"));
    connect(saveAct, SIGNAL(triggered()), this, SLOT(save()));
    ///Setup Close action
    closeAct = menu.addAction(tr("&Close"));
    closeAct->setShortcut(tr("Ctrl+c"));
    connect(closeAct, SIGNAL(triggered()), this, SLOT(close()));

    menu.exec(event->globalPos());
}

void DGVImage::paintEvent(QPaintEvent *event)
{
    QLabel::paintEvent(event);
}
